package com.lzy.sso.cas.config;

import com.lzy.sso.cas.authenticator.Authenticator;
import com.lzy.sso.cas.authenticator.Realm;
import com.lzy.sso.cas.authenticator.impl.DefaultRealm;
import com.lzy.sso.cas.authenticator.impl.RoleBasedAuthenticator;
import com.lzy.sso.cas.controller.AuthenticationController;
import com.lzy.sso.cas.generator.TokenGenerator;
import com.lzy.sso.cas.generator.impl.UUIDTokenGenerator;
import com.lzy.sso.cas.matcher.Encryptor;
import com.lzy.sso.cas.matcher.Matcher;
import com.lzy.sso.cas.matcher.impl.DefaultEncryptor;
import com.lzy.sso.cas.matcher.impl.DefaultMatcher;
import com.lzy.sso.cas.property.AuthenticationProperties;
import com.lzy.sso.cas.service.AuthenticationService;
import com.lzy.sso.cas.service.impl.JWTAuthenticationService;
import com.lzy.sso.cas.service.impl.SessionAuthenticationService;
import com.lzy.sso.cas.store.TokenManagement;
import com.lzy.sso.cas.store.impl.LocalTokenManagement;
import com.lzy.sso.cas.store.impl.RedisTokenManagement;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;


/**
 * @Author: lzy
 * @Date: 2022/4/27 11:45
 * @Description: 自动装配
 */

@Slf4j
@Configuration
//@EnableRedisHttpSession
@EnableConfigurationProperties(AuthenticationProperties.class)
public class AuthenticationAutoConfiguration {

    private AuthenticationProperties properties;

    @Autowired
    public AuthenticationAutoConfiguration(AuthenticationProperties properties){
        this.properties=properties;
        log.info("正在启动CAS服务...");
    }

    /**
     * 主处理接口
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationController.class)
    public AuthenticationController authenticationController(){
        return new AuthenticationController();
    }

    /**
     * 会话服务
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(AuthenticationService.class)
    public AuthenticationService authenticationService(){
        AuthenticationService authentication=null;

        String type = properties.getType();
        if("jwt".equals(type) || "json with token".equals(type)){
            authentication = new JWTAuthenticationService();
        } else {
            authentication = new SessionAuthenticationService();
        }

        return authentication;
    }

    /**
     * 登录管理器
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(Authenticator.class)
    public Authenticator authenticator(){
        return new RoleBasedAuthenticator();
    }

    /**
     * token管理器
     * @return
     */
    @Bean
    @ConditionalOnClass(AuthenticationService.class)
    @ConditionalOnMissingBean(TokenManagement.class)
    public TokenManagement tokenManagement(){
        TokenManagement tokenManagement=null;

        String store = properties.getStore();
        if("redis".equals(store)){
            tokenManagement=new RedisTokenManagement();
        } else {
            tokenManagement=new LocalTokenManagement();
        }

        return tokenManagement;
    }

    /**
     * 配置token生成器
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(TokenGenerator.class)
    public TokenGenerator tokenGenerator(){
        return new UUIDTokenGenerator();
    }

    /**
     * 使用lettuce操作redis
     * @param connectionFactory
     * @return
     */
    @Bean("casRedisTemplate")
    @ConditionalOnClass(LettuceConnectionFactory.class)
    public RedisTemplate<String, Object>
    CASRedisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }

    /**
     * cookie自定义
     * @return
     */
    @Bean
    @ConditionalOnClass(RedisHttpSessionConfiguration.class)
    @ConditionalOnMissingBean(CookieSerializer.class)
    public CookieSerializer cookieSerializer(){
        DefaultCookieSerializer cookieSerializer=new DefaultCookieSerializer();
        cookieSerializer.setCookieName(properties.getCookieName());
        return cookieSerializer;
    }

    /**
     * 认证授权
     * @return
     */
    @Bean
    @ConditionalOnMissingBean(Realm.class)
    public Realm realm(){
        return new DefaultRealm();
    }

    /**
     * 匹配器
     * @return
     */
    @Bean
    public Matcher matcher(){
        return new DefaultMatcher();
    }

    /**
     * 加密规则
     * @return
     */
    @Bean
    public Encryptor encryptor(){
        return new DefaultEncryptor();
    }
}
